from kivy.logger import Logger

from irc.client import NickMask

from amgineirc.viewModel.channels.sendReceiveViewModel import SendReceiveViewModel

class PrvmsgViewModel(SendReceiveViewModel):
    """
    the target is the other nick that the user is privmsg(ing) with.
    """

    def __init__(self,
                 view, send_view, receive_view,
                 connection,
                 target,
                 trusted_user_record,
                 appdata):
        SendReceiveViewModel.__init__(self,
                                      view, send_view,
                                      receive_view,
                                      connection,
                                      target,
                                      appdata)
        self._last_source = ''
        self._default_command = '/privmsg'
        # is this still needed?
        nmask = NickMask(target)
        self._default_target_nick = nmask.nick
        self._logged_in = False
        if trusted_user_record is not None:
            # find the rules
            self._amgine = appdata['rules'].get(trusted_user_record['rule_name'])
        else:
            self._amgine = None
        # get the nick for this server
        record = appdata['servers'].get_server(self._connection.server)
        if record is not None:
            self._nick = record['nick']
        else:
            self._nick = ''

    def nick_change(self, old_nick, new_nick):
        # called by ConnectionsViewModel
        # update the target if needed
        if old_nick == self._target:
            self._target = new_nick
            text = '%s is now %s.' % (old_nick, new_nick)
            message = self._format_new_log_entry('nick', old_nick, old_nick, [text])
            # add the message
            self._receive_view.vm_log(message)
            self._last_source = old_nick
            return True
        elif old_nick == self._nick:
            text = 'You are now %s.' % (new_nick)
            message = self._format_new_log_entry('nick', old_nick, old_nick, [text])
            # add the message
            self._receive_view.vm_log(message)
            self._last_source = old_nick
            return True
        else:
            return False

    # client methods

    def handle_on_connect(self, connection):
        SendReceiveViewModel.handle_on_connect(self, connection)
        message = 'You are now connected to %s.' % (self.server)
        self.handle_client_event(self.target, 'connected', self.server, self.server, [message])

    def handle_on_disconnect(self):
        self._logged_in = False
        message = 'You are now disconnected from %s.' % (self.server)
        self.handle_client_event(self.target, 'disconnected', self.server, self.server, [message])
        SendReceiveViewModel.handle_on_disconnect(self)

    # recieve view methods
    
    def handle_client_event(self, evtarget, evtype, evserver, evsource, evargs):
        """
        handle an event from the client
        store event and start the logger to the view
        """
        if evtype == 'exception':
            message = self._format_new_log_entry(evtype, evtarget, evsource, evargs)
        elif evtype == 'nick':
            # handle this like the server connection does
            nmask = NickMask(evsource)
            old_nick = nmask.nick
            Logger.debug('PrvmsgViewModel.handle_client_event: nick %s, %s' % (old_nick, evtarget))
            self._appdata['connection_vm'].update_nick_change(self.server, old_nick, evtarget)
            return
        else:
            if evsource == 'NickServ' and self._target == evsource and self._logged_in is False:
                # bind self._logged_in to self.connected
                self._login()
                return
            elif evtype == 'privmsg':
                if self._amgine is not None:
                    unsafe = self._amgine.apply_irc_receive_rules(evargs[0])
                    safe_display = evargs[0][:5] + '...' + evargs[0][-5:]
                    message = unsafe + '\n' + safe_display
                else:
                    message = evargs[0]
                if evsource != self._last_source:
                    # start a new log entry
                    # format the message with type, target, source
                    message = self._format_new_log_entry(evtype, evtarget, evsource, [message])
            else:
                if evsource == self._last_source:
                    # continue from the last log entry
                    message = ' '.join(evargs)
                else:
                    # start a new log entry
                    # format the message with type, target, source
                    message = self._format_new_log_entry(evtype, evtarget, evsource, evargs)
        # add the message
        self._receive_view.vm_log(message)
        self._last_source = evsource
        # show page as updated
        if self.connected and self._appdata['connection_vm'] is not None:
            self._appdata['connection_vm'].page_updated(self._connection.server, self._target)

    # send view methods

    def _message_split(self, message):
        words = message.split()
        lines = []
        i = 0
        len_words = len(words)
        while i < len_words:
            len_line = 0
            line = []
            while len_line < self._amgine._irc_pre_apply_maxlen:
                wlen = len(words[i])
                if len_line + wlen <= self._amgine._irc_pre_apply_maxlen:
                    line.append(words[i])
                    len_line += wlen
                    i += 1
                    if i == len_words:
                        lines.append(line)
                        break
                else:
                    lines.append(line)
                    break
        return [' '.join(i) for i in lines]

    def _send_privmsg(self, target, message=''):
        # message is user input
        # if this message goes to another user
        #   then open a window for this private message if not already open
        if target != self._target:
            clipped = message[:480]
            unsafe = clipped.replace('\r\n', ' ')\
                     .replace('\r', ' ')\
                     .replace('\n', ' ')
            self._appdata['connection_vm'].add_privmsg_connection(self._connection,
                                                                  target,
                                                                  send_message=unsafe)
        else:
            # this message goes to this channel
            display_source = 'You to %s' % self.target
            unsafe = message.strip()
            if len(unsafe):
                if self._amgine is not None:
                    msgs = self._message_split(unsafe)
                    for i in msgs:
                        display = i + '\n'
                        safe_list = self._amgine.apply_irc_send_rules(i)
                        # accumulate the display text
                        for j in safe_list:
                            safe_display = j[:5] + '...' + j[-5:]
                            display += safe_display + ' '
                            # send the safe message
                            self._connection.privmsg(target, j)
                        self.handle_client_event(self._connection.server,
                                                 self._target,
                                                 'input',
                                                 display_source,
                                                 [display])
                else:
                    # send an unsafe message
                    clipped = unsafe[:480]
                    unsafe = clipped.replace('\r\n', ' ') \
                             .replace('\r', ' ') \
                             .replace('\n', ' ')
                    self._connection.privmsg(target, unsafe)
                    display = unsafe
                    # display back to the user
                    self.handle_client_event(self._connection.server,
                                             self._target,
                                             'input',
                                             display_source,
                                             [display])

    def handle_view_send(self, message):
        """ the user has entered text to send.
        send the message over the network.
        """
        if not self.connected:
            return
        try:
            m = message.strip()
            if self._handle_view_send_privmsg(m):
                return
            else:
                # let the super handle it
                if not SendReceiveViewModel.handle_view_send(self, message):
                    message = 'Unknown IRC command.'
                # display the command
                self.handle_client_event(self._target,
                                         'input',
                                         self._connection.server,
                                         self._nick,
                                         [message])
        except Exception as e:
            message = repr(e)
            self.handle_client_event(self._target,
                                     'exception',
                                     self._connection.server,
                                     '',
                                     [message])

    # initial open methods

    def receive_opening_privmsg(self, message):
        if self.connected and len(message) > 0:
            self.handle_client_event(self._target,
                                     'privmsg',
                                     self._connection.server,
                                     self._target,
                                     [message])

    def send_opening_privmsg(self, message):
        if self.connected and len(message) > 0:
            # send the message
            self._connection.privmsg(self._target, message)
            # display the message
            self.handle_client_event(self._target,
                                     'input',
                                     self._connection.server,
                                     self._nick,
                                     [message])

    # private methods

    def _login(self):
        # login the user
        self._logged_in = True
        record = self._appdata['servers'].data[self._connection.server]
        nick_password = record['nick_password']
        if len(nick_password) > 0:
            msg = "IDENTIFY %s" % (nick_password)
            self._send_privmsg('NickServ', msg)
